import {classnames, delay, designComponent, iHTMLDivElement, onBeforeUnmount, reactive, useClassCache, useRefs, watch} from "@peryl/react-compose";
import './AppNavigator.scss';
import {Corner, createScrollDraggier, Dropdown, DropdownOption, i18n, Icon, Scroll} from "plain-design";
import {microApp} from "../microApp";
import AppNavigatorLocale from "./AppNavigator.locale";
import {debounce} from '@peryl/utils/debounce';
import {addWindowListener} from "@peryl/utils/addWindowListener";
import {hasClass} from "@peryl/utils/hasClass";
import {iMicroTabMeta} from "@peryl/micro-web";
import {getRectAutoFormat} from '@peryl/utils/getRectAutoFormat';

i18n.setLangs(AppNavigatorLocale);

export const AppNavigator = designComponent({
  name: 'app-navigator',
  props: {},
  setup({ props }) {

    const { refs, onRef } = useRefs({ scroll: Scroll, el: iHTMLDivElement });

    const state = reactive({
      hasScroll: null as null | boolean,
    });

    const classes = useClassCache(() => [
      'app-navigator',
      {
        'app-navigator-scroll': !!state.hasScroll,
        'app-navigator-not-ready': state.hasScroll == null,
      }
    ]);

    const handler = {
      reset: async () => {
        await delay();
        if (!refs.scroll) {
          return;
        }
        const hasScroll = refs.scroll.state.hostWidth < refs.scroll.state.contentWidth;
        if (state.hasScroll != hasScroll) {
          state.hasScroll = hasScroll;
        }
      },
      debounceReset: debounce(() => handler.reset(), 50),
      scrollPrev: () => {
        if (!refs.scroll) {
          return;
        }
        refs.scroll.methods.scrollLeft(
          refs.scroll.freezeState.wrapperScrollLeft - Math.floor(refs.scroll.state.hostWidth / 2),
          500,
        );
      },
      scrollNext: () => {
        if (!refs.scroll) {
          return;
        }
        refs.scroll.methods.scrollLeft(
          refs.scroll.freezeState.wrapperScrollLeft + Math.floor(refs.scroll.state.hostWidth / 2),
          500,
        );
      },
    };

    onBeforeUnmount(addWindowListener('resize', handler.debounceReset));

    const scrollDraggier = createScrollDraggier({
      props: { horizontal: true },
      getScroll: () => refs.scroll!,
      dataModel: {
        get value() {
          return microApp.state.tabs;
        },
        set value(newVal) {
          microApp.state.tabs = newVal;
          microApp.cache.save();
        }
      },
      getItemElements: () => Array.from(refs.scroll?.refs.content?.querySelectorAll('[data-tab-id]') || []),
      onDraggierTap: ({ dragStaticState }) => microApp.showTab(microApp.state.tabs[dragStaticState.dragIndex]),
      onDraggierStart: ({ dragStaticState }) => {
        dragStaticState.dragElementShadow.setAttribute('data-shadow-item', String(dragStaticState.dragIndex));
      },
    });

    watch(() => microApp.state.current?.tab.id, async currentTabId => {
      if (!currentTabId) {
        return;
      }
      if (!refs.scroll) {
        return refs.scroll;
      }
      await delay(78);

      const activeTabElement = refs.scroll.refs.content!.querySelector(`[data-tab-id="${currentTabId}"]`) as undefined | HTMLDivElement;

      if (!activeTabElement) {
        return;
      }

      const hostRect = getRectAutoFormat(refs.scroll.refs.host!);
      const tabRect = getRectAutoFormat(activeTabElement);

      if (!(tabRect.left >= hostRect.left && tabRect.right <= hostRect.right)) {
        refs.scroll.methods.scrollLeft(activeTabElement.offsetLeft - (hostRect.width - tabRect.width));
      }
    });

    return () => {
      handler.debounceReset();
      return (
        <div className={classes.value} ref={onRef.el}>
          <Scroll scrollX scrollY={false} fitHostHeight scrollbarSize={0} ref={onRef.scroll}>
            <div className="app-navigator-list">
              {microApp.state.tabs.map((tab, index) => {
                const isActive = microApp.state.current?.tab.id == tab.id;
                const isPrevActive = microApp.state.current?.tab.id == microApp.state.tabs[index + 1]?.id;
                const isNextActive = microApp.state.current?.tab.id == microApp.state.tabs[index - 1]?.id;
                return (
                  <div
                    key={tab.id}
                    data-tab-id={tab.id}
                    style={scrollDraggier.getItemStyles(index)}
                    className="app-navigator-item-wrapper"
                  >
                    <Dropdown
                      trigger="contextmenu"
                      size="mini"
                      v-slots={{
                        default: () => (
                          <div
                            className={classnames([
                              'app-navigator-item',
                              {
                                'app-navigator-item-prev-active': isPrevActive,
                                'app-navigator-item-next-active': isNextActive,
                              }
                            ])}
                            onMouseDown={e => {
                              const targetElement = e.target as HTMLDivElement;
                              const tagName = targetElement.tagName.toLowerCase();
                              if (tagName === 'svg' ||
                                tagName === 'path' ||
                                hasClass(targetElement, 'app-navigator-item-close')) {
                                return;
                              }
                              scrollDraggier.start(e, index);
                            }}
                            data-active={String(isActive)}
                          >
                            {isActive && (index != 0 || state.hasScroll) && (
                              <Corner type="bottom-left" className="app-navigator-item-prepend"/>
                            )}
                            <div className="app-navigator-item-inner">
                              {!!tab.icon && <Icon icon={tab.icon}/>}
                              <span>{i18n.$intl(tab.label).d(tab.label)}</span>
                              <div className="app-navigator-item-close" onClick={(e) => {
                                e.stopPropagation();
                                e.preventDefault();
                                microApp.closeTab(tab);
                              }}>
                                <Icon icon="pi-close"/>
                              </div>
                            </div>
                            {isActive && (
                              <Corner type="bottom-right" className="app-navigator-item-append"/>
                            )}
                          </div>
                        ),
                        popper: () => {
                          let opts: { label: string, icon: string, handler: () => void }[] = [];

                          opts.push({ label: i18n.$intl('appNavigator.close').d('关闭当前标签'), icon: 'pi-close', handler: () => microApp.closeTab(tab) });
                          opts.push({ label: i18n.$intl('appNavigator.fresh').d('刷新当前标签'), icon: 'pi-refresh', handler: () => microApp.refreshTab(tab) });
                          opts.push({ label: i18n.$intl('appNavigator.copy').d('复制当前标签'), icon: 'pi-copy', handler: () => microApp.copyTab(tab) });
                          opts.push({ label: i18n.$intl('appNavigator.closeTabsToTheLeft').d('关闭左侧标签'), icon: 'pi-to-left', handler: () => microApp.closeLeftTabs(tab) });
                          opts.push({ label: i18n.$intl('appNavigator.closeTabsToTheRight').d('关闭右侧标签'), icon: 'pi-to-right', handler: () => microApp.closeRightTabs(tab) });
                          opts.push({ label: i18n.$intl('appNavigator.closeOtherTabs').d('关闭其他标签'), icon: 'pi-delete', handler: () => microApp.closeOtherTabs(tab) });

                          return opts.map(i => (
                            <DropdownOption key={i.label} icon={i.icon} label={i.label} onClick={i.handler}/>
                          ));
                        },
                      }}
                    />
                  </div>
                );
              })}
            </div>
          </Scroll>
          {state.hasScroll && <>
            <div className="app-navigator-prev-button" onClick={handler.scrollPrev}><Icon icon="pi-to-left"/></div>
            <div className="app-navigator-next-button" onClick={handler.scrollNext}><Icon icon="pi-to-right"/></div>
          </>}
        </div>
      );
    };
  },
});

interface iDragRect {
  id: string,
  index: number
  width: number
  left: number,
  offsetLeft: number
  el: HTMLDivElement
  tabMeta: iMicroTabMeta,
}
